package org.artifact.core.util;

public class BitUtil {



    //首先分析第一个方法，仅仅用于获取byte数组中off坐标下是否存在不为0的数据,因为boolean类型只占1位，即1bit
    public static boolean getBoolean(byte[] b, int off) {
        return b[off] != 0;
    }

    /**
     * 第二个方法，获取byte数组中连续的两个内存地址数据，我们知道计算机底层存储数据是以二进制存储的，一位等于1bit,其中1byte=8bit，
     * 而1char=2byte,并且在类型声确定之初就已经获取了固定的内存长度，所以需要获取两个连续byte的内存才满足占位16的char类型，我们知道
     * 0xFF是以16进制表示的数据，其计算机存储底层数据为11111111，假如此时获取的byte[off]底层数据为00000001，byte[off+1]底层数据为00110011
     * 计算机为32位，64位数据长一些就用32位
     * 进行运算获取低八位数据：
     * 00000000 00000000 00000000 00110011
     * 00000000 00000000 00000000 11111111
     * -----------------------------------      &
     * 00000000 00000000 00000000 00110011
     * 高八位数据为：
     * 00000000 00000000 00000000 00000001
     * ----------------------------------   <<8
     * 00000000 00000000 00000001 00000000
     * 第三步：
     * 00000000 00000000 00000000 00110011
     * 00000000 00000000 00000001 00000000
     * ------------------------------------    +
     * 00000000 00000000 00000001 00110011
     * 最后转换为char类型截取后16位后为00000001 00110011,输出为ĳ
     * 其中0xff是为了保证非有效位为0，防止负数时自动补1
     */
    public static char getChar(byte[] b, int off) {
        return (char) ((b[off + 1] & 0xFF) +
                (b[off] << 8));
    }

    //同上
    public static short getShort(byte[] b, int off) {
        return (short) ((b[off + 1] & 0xFF) +
                (b[off] << 8));
    }

    //原理同上，只是位数变为32位
    public static int getInt(byte[] b, int off) {
        return ((b[off + 3] & 0xFF)      ) +
                ((b[off + 2] & 0xFF) <<  8) +
                ((b[off + 1] & 0xFF) << 16) +
                ((b[off    ]       ) << 24);
    }

    //同上，只是再调用intBitsToFloat把int转换为float
    public static float getFloat(byte[] b, int off) {
        return Float.intBitsToFloat(getInt(b, off));
    }

    //同上，位数变为64位
    public static long getLong(byte[] b, int off) {
        return ((b[off + 7] & 0xFFL)      ) +
                ((b[off + 6] & 0xFFL) <<  8) +
                ((b[off + 5] & 0xFFL) << 16) +
                ((b[off + 4] & 0xFFL) << 24) +
                ((b[off + 3] & 0xFFL) << 32) +
                ((b[off + 2] & 0xFFL) << 40) +
                ((b[off + 1] & 0xFFL) << 48) +
                (((long) b[off])      << 56);
    }

    //同上，再调用longBitsToDouble转换为double
    public static double getDouble(byte[] b, int off) {
        return Double.longBitsToDouble(getLong(b, off));
    }

    //把数据置于内存byte数组中，boolean占1bit
    public static void putBoolean(byte[] b, int off, boolean val) {
        b[off] = (byte) (val ? 1 : 0);
    }

    /**
     * 把char类型置于连续内存的byte数组中，假定传入的char类型的val=a,其计算机底层存储二进制位00000000 01100001
     *  第一步将val转换为byte类型，截取低八位为：01100001存储在byte[off+1]
     *  第二步将val不带符号右移8位：
     *  00000000 00000000 00000000 01100001
     *  ------------------    >>>8
     *  00000000 00000000 00000000 00000000
     *  然后强转，将00000000 00000000 00000000 00000000 截取为00000000,存储在byte[off]
     *
     */
    public static void putChar(byte[] b, int off, char val) {
        b[off + 1] = (byte) (val      );
        b[off    ] = (byte) (val >>> 8);
    }
    //同上
    public static void putShort(byte[] b, int off, short val) {
        b[off + 1] = (byte) (val      );
        b[off    ] = (byte) (val >>> 8);
    }
    //同上
    public static void putInt(byte[] b, int off, int val) {
        b[off + 3] = (byte) (val       );
        b[off + 2] = (byte) (val >>>  8);
        b[off + 1] = (byte) (val >>> 16);
        b[off    ] = (byte) (val >>> 24);
    }
    //同上
    public static void putFloat(byte[] b, int off, float val) {
        putInt(b, off,  Float.floatToIntBits(val));
    }
    //同上
    public static void putLong(byte[] b, int off, long val) {
        b[off + 7] = (byte) (val       );
        b[off + 6] = (byte) (val >>>  8);
        b[off + 5] = (byte) (val >>> 16);
        b[off + 4] = (byte) (val >>> 24);
        b[off + 3] = (byte) (val >>> 32);
        b[off + 2] = (byte) (val >>> 40);
        b[off + 1] = (byte) (val >>> 48);
        b[off    ] = (byte) (val >>> 56);
    }
    //同上
    public static void putDouble(byte[] b, int off, double val) {
        putLong(b, off, Double.doubleToLongBits(val));
    }
}